home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 22 / PCPP #22.iso / Quake2 / q2source_12_11 / utils3 / bsp / qbsp3 / map.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-18  |  21.9 KB  |  998 lines

  1. // map.c
  2.  
  3. #include "qbsp.h"
  4.  
  5. extern qboolean onlyents;
  6.  
  7. int            nummapbrushes;
  8. mapbrush_t    mapbrushes[MAX_MAP_BRUSHES];
  9.  
  10. int            nummapbrushsides;
  11. side_t        brushsides[MAX_MAP_SIDES];
  12. brush_texture_t    side_brushtextures[MAX_MAP_SIDES];
  13.  
  14. int            nummapplanes;
  15. plane_t        mapplanes[MAX_MAP_PLANES];
  16.  
  17. #define    PLANE_HASHES    1024
  18. plane_t        *planehash[PLANE_HASHES];
  19.  
  20. vec3_t        map_mins, map_maxs;
  21.  
  22. // undefine to make plane finding use linear sort
  23. #define    USE_HASHING
  24.  
  25. void TestExpandBrushes (void);
  26.  
  27. int        c_boxbevels;
  28. int        c_edgebevels;
  29.  
  30. int        c_areaportals;
  31.  
  32. int        c_clipbrushes;
  33.  
  34. /*
  35. =============================================================================
  36.  
  37. PLANE FINDING
  38.  
  39. =============================================================================
  40. */
  41.  
  42.  
  43. /*
  44. =================
  45. PlaneTypeForNormal
  46. =================
  47. */
  48. int    PlaneTypeForNormal (vec3_t normal)
  49. {
  50.     vec_t    ax, ay, az;
  51.     
  52. // NOTE: should these have an epsilon around 1.0?        
  53.     if (normal[0] == 1.0 || normal[0] == -1.0)
  54.         return PLANE_X;
  55.     if (normal[1] == 1.0 || normal[1] == -1.0)
  56.         return PLANE_Y;
  57.     if (normal[2] == 1.0 || normal[2] == -1.0)
  58.         return PLANE_Z;
  59.         
  60.     ax = fabs(normal[0]);
  61.     ay = fabs(normal[1]);
  62.     az = fabs(normal[2]);
  63.     
  64.     if (ax >= ay && ax >= az)
  65.         return PLANE_ANYX;
  66.     if (ay >= ax && ay >= az)
  67.         return PLANE_ANYY;
  68.     return PLANE_ANYZ;
  69. }
  70.  
  71. /*
  72. ================
  73. PlaneEqual
  74. ================
  75. */
  76. #define    NORMAL_EPSILON    0.00001
  77. #define    DIST_EPSILON    0.01
  78. qboolean    PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
  79. {
  80. #if 1
  81.     if (
  82.        fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
  83.     && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
  84.     && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
  85.     && fabs(p->dist - dist) < DIST_EPSILON )
  86.         return true;
  87. #else
  88.     if (p->normal[0] == normal[0]
  89.         && p->normal[1] == normal[1]
  90.         && p->normal[2] == normal[2]
  91.         && p->dist == dist)
  92.         return true;
  93. #endif
  94.     return false;
  95. }
  96.  
  97. /*
  98. ================
  99. AddPlaneToHash
  100. ================
  101. */
  102. void    AddPlaneToHash (plane_t *p)
  103. {
  104.     int        hash;
  105.  
  106.     hash = (int)fabs(p->dist) / 8;
  107.     hash &= (PLANE_HASHES-1);
  108.  
  109.     p->hash_chain = planehash[hash];
  110.     planehash[hash] = p;
  111. }
  112.  
  113. /*
  114. ================
  115. CreateNewFloatPlane
  116. ================
  117. */
  118. int CreateNewFloatPlane (vec3_t normal, vec_t dist)
  119. {
  120.     plane_t    *p, temp;
  121.  
  122.     if (VectorLength(normal) < 0.5)
  123.         Error ("FloatPlane: bad normal");
  124.     // create a new plane
  125.     if (nummapplanes+2 > MAX_MAP_PLANES)
  126.         Error ("MAX_MAP_PLANES");
  127.  
  128.     p = &mapplanes[nummapplanes];
  129.     VectorCopy (normal, p->normal);
  130.     p->dist = dist;
  131.     p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
  132.  
  133.     VectorSubtract (vec3_origin, normal, (p+1)->normal);
  134.     (p+1)->dist = -dist;
  135.  
  136.     nummapplanes += 2;
  137.  
  138.     // allways put axial planes facing positive first
  139.     if (p->type < 3)
  140.     {
  141.         if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
  142.         {
  143.             // flip order
  144.             temp = *p;
  145.             *p = *(p+1);
  146.             *(p+1) = temp;
  147.  
  148.             AddPlaneToHash (p);
  149.             AddPlaneToHash (p+1);
  150.             return nummapplanes - 1;
  151.         }
  152.     }
  153.  
  154.     AddPlaneToHash (p);
  155.     AddPlaneToHash (p+1);
  156.     return nummapplanes - 2;
  157. }
  158.  
  159. /*
  160. ==============
  161. SnapVector
  162. ==============
  163. */
  164. void    SnapVector (vec3_t normal)
  165. {
  166.     int        i;
  167.  
  168.     for (i=0 ; i<3 ; i++)
  169.     {
  170.         if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
  171.         {
  172.             VectorClear (normal);
  173.             normal[i] = 1;
  174.             break;
  175.         }
  176.         if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
  177.         {
  178.             VectorClear (normal);
  179.             normal[i] = -1;
  180.             break;
  181.         }
  182.     }
  183. }
  184.  
  185. /*
  186. ==============
  187. SnapPlane
  188. ==============
  189. */
  190. void    SnapPlane (vec3_t normal, vec_t *dist)
  191. {
  192.     SnapVector (normal);
  193.  
  194.     if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
  195.         *dist = Q_rint(*dist);
  196. }
  197.  
  198. /*
  199. =============
  200. FindFloatPlane
  201.  
  202. =============
  203. */
  204. #ifndef USE_HASHING
  205. int        FindFloatPlane (vec3_t normal, vec_t dist)
  206. {
  207.     int        i;
  208.     plane_t    *p;
  209.  
  210.     SnapPlane (normal, &dist);
  211.     for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
  212.     {
  213.         if (PlaneEqual (p, normal, dist))
  214.             return i;
  215.     }
  216.  
  217.     return CreateNewFloatPlane (normal, dist);
  218. }
  219. #else
  220. int        FindFloatPlane (vec3_t normal, vec_t dist)
  221. {
  222.     int        i;
  223.     plane_t    *p;
  224.     int        hash, h;
  225.  
  226.     SnapPlane (normal, &dist);
  227.     hash = (int)fabs(dist) / 8;
  228.     hash &= (PLANE_HASHES-1);
  229.  
  230.     // search the border bins as well
  231.     for (i=-1 ; i<=1 ; i++)
  232.     {
  233.         h = (hash+i)&(PLANE_HASHES-1);
  234.         for (p = planehash[h] ; p ; p=p->hash_chain)
  235.         {
  236.             if (PlaneEqual (p, normal, dist))
  237.                 return p-mapplanes;
  238.         }
  239.     }
  240.  
  241.     return CreateNewFloatPlane (normal, dist);
  242. }
  243. #endif
  244.  
  245. /*
  246. ================
  247. PlaneFromPoints
  248. ================
  249. */
  250. int PlaneFromPoints (int *p0, int *p1, int *p2)
  251. {
  252.     vec3_t    t1, t2, normal;
  253.     vec_t    dist;
  254.  
  255.     VectorSubtract (p0, p1, t1);
  256.     VectorSubtract (p2, p1, t2);
  257.     CrossProduct (t1, t2, normal);
  258.     VectorNormalize (normal, normal);
  259.  
  260.     dist = DotProduct (p0, normal);
  261.  
  262.     return FindFloatPlane (normal, dist);
  263. }
  264.  
  265.  
  266. //====================================================================
  267.  
  268.  
  269. /*
  270. ===========
  271. BrushContents
  272. ===========
  273. */
  274. int    BrushContents (mapbrush_t *b)
  275. {
  276.     int            contents;
  277.     side_t        *s;
  278.     int            i;
  279.     int            trans;
  280.  
  281.     s = &b->original_sides[0];
  282.     contents = s->contents;
  283.     trans = texinfo[s->texinfo].flags;
  284.     for (i=1 ; i<b->numsides ; i++, s++)
  285.     {
  286.         s = &b->original_sides[i];
  287.         trans |= texinfo[s->texinfo].flags;
  288.         if (s->contents != contents)
  289.         {
  290.             printf ("Entity %i, Brush %i: mixed face contents\n"
  291.                 , b->entitynum, b->brushnum);
  292.             break;
  293.         }
  294.     }
  295.  
  296.     // if any side is translucent, mark the contents
  297.     // and change solid to window
  298.     if ( trans & (SURF_TRANS33|SURF_TRANS66) )
  299.     {
  300.         contents |= CONTENTS_TRANSLUCENT;
  301.         if (contents & CONTENTS_SOLID)
  302.         {
  303.             contents &= ~CONTENTS_SOLID;
  304.             contents |= CONTENTS_WINDOW;
  305.         }
  306.     }
  307.  
  308.     return contents;
  309. }
  310.  
  311.  
  312. //============================================================================
  313.  
  314. /*
  315. =================
  316. AddBrushBevels
  317.  
  318. Adds any additional planes necessary to allow the brush to be expanded
  319. against axial bounding boxes
  320. =================
  321. */
  322. void AddBrushBevels (mapbrush_t *b)
  323. {
  324.     int        axis, dir;
  325.     int        i, j, k, l, order;
  326.     side_t    sidetemp;
  327.     brush_texture_t    tdtemp;
  328.     side_t    *s, *s2;
  329.     vec3_t    normal;
  330.     float    dist;
  331.     winding_t    *w, *w2;
  332.     vec3_t    vec, vec2;
  333.     float    d;
  334.  
  335.     //
  336.     // add the axial planes
  337.     //
  338.     order = 0;
  339.     for (axis=0 ; axis <3 ; axis++)
  340.     {
  341.         for (dir=-1 ; dir <= 1 ; dir+=2, order++)
  342.         {
  343.             // see if the plane is allready present
  344.             for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
  345.             {
  346.                 if (mapplanes[s->planenum].normal[axis] == dir)
  347.                     break;
  348.             }
  349.  
  350.             if (i == b->numsides)
  351.             {    // add a new side
  352.                 if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
  353.                     Error ("MAX_MAP_BRUSHSIDES");
  354.                 nummapbrushsides++;
  355.                 b->numsides++;
  356.                 VectorClear (normal);
  357.                 normal[axis] = dir;
  358.                 if (dir == 1)
  359.                     dist = b->maxs[axis];
  360.                 else
  361.                     dist = -b->mins[axis];
  362.                 s->planenum = FindFloatPlane (normal, dist);
  363.                 s->texinfo = b->original_sides[0].texinfo;
  364.                 s->contents = b->original_sides[0].contents;
  365.                 s->bevel = true;
  366.                 c_boxbevels++;
  367.             }
  368.  
  369.             // if the plane is not in it canonical order, swap it
  370.             if (i != order)
  371.             {
  372.                 sidetemp = b->original_sides[order];
  373.                 b->original_sides[order] = b->original_sides[i];
  374.                 b->original_sides[i] = sidetemp;
  375.  
  376.                 j = b->original_sides - brushsides;
  377.                 tdtemp = side_brushtextures[j+order];
  378.                 side_brushtextures[j+order] = side_brushtextures[j+i];
  379.                 side_brushtextures[j+i] = tdtemp;
  380.             }
  381.         }
  382.     }
  383.  
  384.     //
  385.     // add the edge bevels
  386.     //
  387.     if (b->numsides == 6)
  388.         return;        // pure axial
  389.  
  390.     // test the non-axial plane edges
  391.     for (i=6 ; i<b->numsides ; i++)
  392.     {
  393.         s = b->original_sides + i;
  394.         w = s->winding;
  395.         if (!w)
  396.             continue;
  397.         for (j=0 ; j<w->numpoints ; j++)
  398.         {
  399.             k = (j+1)%w->numpoints;
  400.             VectorSubtract (w->p[j], w->p[k], vec);
  401.             if (VectorNormalize (vec, vec) < 0.5)
  402.                 continue;
  403.             SnapVector (vec);
  404.             for (k=0 ; k<3 ; k++)
  405.                 if ( vec[k] == -1 || vec[k] == 1)
  406.                     break;    // axial
  407.             if (k != 3)
  408.                 continue;    // only test non-axial edges
  409.  
  410.             // try the six possible slanted axials from this edge
  411.             for (axis=0 ; axis <3 ; axis++)
  412.             {
  413.                 for (dir=-1 ; dir <= 1 ; dir+=2)
  414.                 {
  415.                     // construct a plane
  416.                     VectorClear (vec2);
  417.                     vec2[axis] = dir;
  418.                     CrossProduct (vec, vec2, normal);
  419.                     if (VectorNormalize (normal, normal) < 0.5)
  420.                         continue;
  421.                     dist = DotProduct (w->p[j], normal);
  422.  
  423.                     // if all the points on all the sides are
  424.                     // behind this plane, it is a proper edge bevel
  425.                     for (k=0 ; k<b->numsides ; k++)
  426.                     {
  427.                         // if this plane has allready been used, skip it
  428.                         if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
  429.                             , normal, dist) )
  430.                             break;
  431.  
  432.                         w2 = b->original_sides[k].winding;
  433.                         if (!w2)
  434.                             continue;
  435.                         for (l=0 ; l<w2->numpoints ; l++)
  436.                         {
  437.                             d = DotProduct (w2->p[l], normal) - dist;
  438.                             if (d > 0.1)
  439.                                 break;    // point in front
  440.                         }
  441.                         if (l != w2->numpoints)
  442.                             break;
  443.                     }
  444.  
  445.                     if (k != b->numsides)
  446.                         continue;    // wasn't part of the outer hull
  447.                     // add this plane
  448.                     if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
  449.                         Error ("MAX_MAP_BRUSHSIDES");
  450.                     nummapbrushsides++;
  451.                     s2 = &b->original_sides[b->numsides];
  452.                     s2->planenum = FindFloatPlane (normal, dist);
  453.                     s2->texinfo = b->original_sides[0].texinfo;
  454.                     s2->contents = b->original_sides[0].contents;
  455.                     s2->bevel = true;
  456.                     c_edgebevels++;
  457.                     b->numsides++;
  458.                 }
  459.             }
  460.         }
  461.     }
  462. }
  463.  
  464.  
  465. /*
  466. ================
  467. MakeBrushWindings
  468.  
  469. makes basewindigs for sides and mins / maxs for the brush
  470. ================
  471. */
  472. qboolean MakeBrushWindings (mapbrush_t *ob)
  473. {
  474.     int            i, j;
  475.     winding_t    *w;
  476.     side_t        *side;
  477.     plane_t        *plane;
  478.  
  479.     ClearBounds (ob->mins, ob->maxs);
  480.  
  481.     for (i=0 ; i<ob->numsides ; i++)
  482.     {
  483.         plane = &mapplanes[ob->original_sides[i].planenum];
  484.         w = BaseWindingForPlane (plane->normal, plane->dist);
  485.         for (j=0 ; j<ob->numsides && w; j++)
  486.         {
  487.             if (i == j)
  488.                 continue;
  489.             if (ob->original_sides[j].bevel)
  490.                 continue;
  491.             plane = &mapplanes[ob->original_sides[j].planenum^1];
  492.             ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
  493.         }
  494.  
  495.         side = &ob->original_sides[i];
  496.         side->winding = w;
  497.         if (w)
  498.         {
  499.             side->visible = true;
  500.             for (j=0 ; j<w->numpoints ; j++)
  501.                 AddPointToBounds (w->p[j], ob->mins, ob->maxs);
  502.         }
  503.     }
  504.  
  505.     for (i=0 ; i<3 ; i++)
  506.     {
  507.         if (ob->mins[0] < -4096 || ob->maxs[0] > 4096)
  508.             printf ("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
  509.         if (ob->mins[0] > 4096 || ob->maxs[0] < -4096)
  510.             printf ("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
  511.     }
  512.  
  513.     return true;
  514. }
  515.  
  516.  
  517. /*
  518. =================
  519. ParseBrush
  520. =================
  521. */
  522. void ParseBrush (entity_t *mapent)
  523. {
  524.     mapbrush_t        *b;
  525.     int            i,j, k;
  526.     int            mt;
  527.     side_t        *side, *s2;
  528.     int            planenum;
  529.     brush_texture_t    td;
  530.     int            planepts[3][3];
  531.  
  532.     if (nummapbrushes == MAX_MAP_BRUSHES)
  533.         Error ("nummapbrushes == MAX_MAP_BRUSHES");
  534.  
  535.     b = &mapbrushes[nummapbrushes];
  536.     b->original_sides = &brushsides[nummapbrushsides];
  537.     b->entitynum = num_entities-1;
  538.     b->brushnum = nummapbrushes - mapent->firstbrush;
  539.  
  540.     do
  541.     {
  542.         if (!GetToken (true))
  543.             break;
  544.         if (!strcmp (token, "}") )
  545.             break;
  546.  
  547.         if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
  548.             Error ("MAX_MAP_BRUSHSIDES");
  549.         side = &brushsides[nummapbrushsides];
  550.  
  551.         // read the three point plane definition
  552.         for (i=0 ; i<3 ; i++)
  553.         {
  554.             if (i != 0)
  555.                 GetToken (true);
  556.             if (strcmp (token, "(") )
  557.                 Error ("parsing brush");
  558.             
  559.             for (j=0 ; j<3 ; j++)
  560.             {
  561.                 GetToken (false);
  562.                 planepts[i][j] = atoi(token);
  563.             }
  564.             
  565.             GetToken (false);
  566.             if (strcmp (token, ")") )
  567.                 Error ("parsing brush");
  568.                 
  569.         }
  570.  
  571.  
  572.         //
  573.         // read the texturedef
  574.         //
  575.         GetToken (false);
  576.         strcpy (td.name, token);
  577.  
  578.         GetToken (false);
  579.         td.shift[0] = atoi(token);
  580.         GetToken (false);
  581.         td.shift[1] = atoi(token);
  582.         GetToken (false);
  583.         td.rotate = atoi(token);    
  584.         GetToken (false);
  585.         td.scale[0] = atof(token);
  586.         GetToken (false);
  587.         td.scale[1] = atof(token);
  588.  
  589.         // find default flags and values
  590.         mt = FindMiptex (td.name);
  591.         td.flags = textureref[mt].flags;
  592.         td.value = textureref[mt].value;
  593.         side->contents = textureref[mt].contents;
  594.         side->surf = td.flags = textureref[mt].flags;
  595.  
  596.         if (TokenAvailable())
  597.         {
  598.             GetToken (false);
  599.             side->contents = atoi(token);
  600.             GetToken (false);
  601.             side->surf = td.flags = atoi(token);
  602.             GetToken (false);
  603.             td.value = atoi(token);
  604.         }
  605.  
  606.         // translucent objects are automatically classified as detail
  607.         if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
  608.             side->contents |= CONTENTS_DETAIL;
  609.         if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
  610.             side->contents |= CONTENTS_DETAIL;
  611.         if (fulldetail)
  612.             side->contents &= ~CONTENTS_DETAIL;
  613.         if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
  614.             | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
  615.             side->contents |= CONTENTS_SOLID;
  616.  
  617.         // hints and skips are never detail, and have no content
  618.         if (side->surf & (SURF_HINT|SURF_SKIP) )
  619.         {
  620.             side->contents = 0;
  621.             side->surf &= ~CONTENTS_DETAIL;
  622.         }
  623.  
  624.  
  625.         //
  626.         // find the plane number
  627.         //
  628.         planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
  629.         if (planenum == -1)
  630.         {
  631.             printf ("Entity %i, Brush %i: plane with no normal\n"
  632.                 , b->entitynum, b->brushnum);
  633.             continue;
  634.         }
  635.  
  636.         //
  637.         // see if the plane has been used already
  638.         //
  639.         for (k=0 ; k<b->numsides ; k++)
  640.         {
  641.             s2 = b->original_sides + k;
  642.             if (s2->planenum == planenum)
  643.             {
  644.                 printf ("Entity %i, Brush %i: duplicate plane\n"
  645.                     , b->entitynum, b->brushnum);
  646.                 break;
  647.             }
  648.             if ( s2->planenum == (planenum^1) )
  649.             {
  650.                 printf ("Entity %i, Brush %i: mirrored plane\n"
  651.                     , b->entitynum, b->brushnum);
  652.                 break;
  653.             }
  654.         }
  655.         if (k != b->numsides)
  656.             continue;        // duplicated
  657.  
  658.         //
  659.         // keep this side
  660.         //
  661.  
  662.         side = b->original_sides + b->numsides;
  663.         side->planenum = planenum;
  664.         side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
  665.             &td, vec3_origin);
  666.  
  667.         // save the td off in case there is an origin brush and we
  668.         // have to recalculate the texinfo
  669.         side_brushtextures[nummapbrushsides] = td;
  670.  
  671.         nummapbrushsides++;
  672.         b->numsides++;
  673.     } while (1);
  674.  
  675.     // get the content for the entire brush
  676.     b->contents = BrushContents (b);
  677.  
  678.     // allow detail brushes to be removed 
  679.     if (nodetail && (b->contents & CONTENTS_DETAIL) )
  680.     {
  681.         b->numsides = 0;
  682.         return;
  683.     }
  684.  
  685.     // allow water brushes to be removed
  686.     if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
  687.     {
  688.         b->numsides = 0;
  689.         return;
  690.     }
  691.  
  692.     // create windings for sides and bounds for brush
  693.     MakeBrushWindings (b);
  694.  
  695.     // brushes that will not be visible at all will never be
  696.     // used as bsp splitters
  697.     if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
  698.     {
  699.         c_clipbrushes++;
  700.         for (i=0 ; i<b->numsides ; i++)
  701.             b->original_sides[i].texinfo = TEXINFO_NODE;
  702.     }
  703.  
  704.     //
  705.     // origin brushes are removed, but they set
  706.     // the rotation origin for the rest of the brushes
  707.     // in the entity.  After the entire entity is parsed,
  708.     // the planenums and texinfos will be adjusted for
  709.     // the origin brush
  710.     //
  711.     if (b->contents & CONTENTS_ORIGIN)
  712.     {
  713.         char    string[32];
  714.         vec3_t    origin;
  715.  
  716.         if (num_entities == 1)
  717.         {
  718.             Error ("Entity %i, Brush %i: origin brushes not allowed in world"
  719.                 , b->entitynum, b->brushnum);
  720.             return;
  721.         }
  722.  
  723.         VectorAdd (b->mins, b->maxs, origin);
  724.         VectorScale (origin, 0.5, origin);
  725.  
  726.         sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  727.         SetKeyValue (&entities[b->entitynum], "origin", string);
  728.  
  729.         VectorCopy (origin, entities[b->entitynum].origin);
  730.  
  731.         // don't keep this brush
  732.         b->numsides = 0;
  733.  
  734.         return;
  735.     }
  736.  
  737.     AddBrushBevels (b);
  738.  
  739.     nummapbrushes++;
  740.     mapent->numbrushes++;        
  741. }
  742.  
  743. /*
  744. ================
  745. MoveBrushesToWorld
  746.  
  747. Takes all of the brushes from the current entity and
  748. adds them to the world's brush list.
  749.  
  750. Used by func_group and func_areaportal
  751. ================
  752. */
  753. void MoveBrushesToWorld (entity_t *mapent)
  754. {
  755.     int            newbrushes;
  756.     int            worldbrushes;
  757.     mapbrush_t    *temp;
  758.     int            i;
  759.  
  760.     // this is pretty gross, because the brushes are expected to be
  761.     // in linear order for each entity
  762.  
  763.     newbrushes = mapent->numbrushes;
  764.     worldbrushes = entities[0].numbrushes;
  765.  
  766.     temp = malloc(newbrushes*sizeof(mapbrush_t));
  767.     memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
  768.  
  769. #if    0        // let them keep their original brush numbers
  770.     for (i=0 ; i<newbrushes ; i++)
  771.         temp[i].entitynum = 0;
  772. #endif
  773.  
  774.     // make space to move the brushes (overlapped copy)
  775.     memmove (mapbrushes + worldbrushes + newbrushes,
  776.         mapbrushes + worldbrushes,
  777.         sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
  778.  
  779.     // copy the new brushes down
  780.     memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
  781.  
  782.     // fix up indexes
  783.     entities[0].numbrushes += newbrushes;
  784.     for (i=1 ; i<num_entities ; i++)
  785.         entities[i].firstbrush += newbrushes;
  786.     free (temp);
  787.  
  788.     mapent->numbrushes = 0;
  789. }
  790.  
  791. /*
  792. ================
  793. ParseMapEntity
  794. ================
  795. */
  796. qboolean    ParseMapEntity (void)
  797. {
  798.     entity_t    *mapent;
  799.     epair_t        *e;
  800.     side_t        *s;
  801.     int            i, j;
  802.     int            startbrush, startsides;
  803.     vec_t        newdist;
  804.     mapbrush_t    *b;
  805.  
  806.     if (!GetToken (true))
  807.         return false;
  808.  
  809.     if (strcmp (token, "{") )
  810.         Error ("ParseEntity: { not found");
  811.     
  812.     if (num_entities == MAX_MAP_ENTITIES)
  813.         Error ("num_entities == MAX_MAP_ENTITIES");
  814.  
  815.     startbrush = nummapbrushes;
  816.     startsides = nummapbrushsides;
  817.  
  818.     mapent = &entities[num_entities];
  819.     num_entities++;
  820.     memset (mapent, 0, sizeof(*mapent));
  821.     mapent->firstbrush = nummapbrushes;
  822.     mapent->numbrushes = 0;
  823. //    mapent->portalareas[0] = -1;
  824. //    mapent->portalareas[1] = -1;
  825.  
  826.     do
  827.     {
  828.         if (!GetToken (true))
  829.             Error ("ParseEntity: EOF without closing brace");
  830.         if (!strcmp (token, "}") )
  831.             break;
  832.         if (!strcmp (token, "{") )
  833.             ParseBrush (mapent);
  834.         else
  835.         {
  836.             e = ParseEpair ();
  837.             e->next = mapent->epairs;
  838.             mapent->epairs = e;
  839.         }
  840.     } while (1);
  841.  
  842.     GetVectorForKey (mapent, "origin", mapent->origin);
  843.  
  844.     //
  845.     // if there was an origin brush, offset all of the planes and texinfo
  846.     //
  847.     if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
  848.     {
  849.         for (i=0 ; i<mapent->numbrushes ; i++)
  850.         {
  851.             b = &mapbrushes[mapent->firstbrush + i];
  852.             for (j=0 ; j<b->numsides ; j++)
  853.             {
  854.                 s = &b->original_sides[j];
  855.                 newdist = mapplanes[s->planenum].dist -
  856.                     DotProduct (mapplanes[s->planenum].normal, mapent->origin);
  857.                 s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
  858.                 s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
  859.                     &side_brushtextures[s-brushsides], mapent->origin);
  860.             }
  861.             MakeBrushWindings (b);
  862.         }
  863.     }
  864.  
  865.     // group entities are just for editor convenience
  866.     // toss all brushes into the world entity
  867.     if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
  868.     {
  869.         MoveBrushesToWorld (mapent);
  870.         mapent->numbrushes = 0;
  871.         return true;
  872.     }
  873.  
  874.     // areaportal entities move their brushes, but don't eliminate
  875.     // the entity
  876.     if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
  877.     {
  878.         char    str[128];
  879.  
  880.         if (mapent->numbrushes != 1)
  881.             Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
  882.  
  883.         b = &mapbrushes[nummapbrushes-1];
  884.         b->contents = CONTENTS_AREAPORTAL;
  885.         c_areaportals++;
  886.         mapent->areaportalnum = c_areaportals;
  887.         // set the portal number as "style"
  888.         sprintf (str, "%i", c_areaportals);
  889.         SetKeyValue (mapent, "style", str);
  890.         MoveBrushesToWorld (mapent);
  891.         return true;
  892.     }
  893.  
  894.     return true;
  895. }
  896.  
  897. //===================================================================
  898.  
  899. /*
  900. ================
  901. LoadMapFile
  902. ================
  903. */
  904. void LoadMapFile (char *filename)
  905. {        
  906.     int        i;
  907.  
  908.     qprintf ("--- LoadMapFile ---\n");
  909.  
  910.     LoadScriptFile (filename);
  911.  
  912.     nummapbrushsides = 0;
  913.     num_entities = 0;
  914.     
  915.     while (ParseMapEntity ())
  916.     {
  917.     }
  918.  
  919.     ClearBounds (map_mins, map_maxs);
  920.     for (i=0 ; i<entities[0].numbrushes ; i++)
  921.     {
  922.         if (mapbrushes[i].mins[0] > 4096)
  923.             continue;    // no valid points
  924.         AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
  925.         AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
  926.     }
  927.  
  928.     qprintf ("%5i brushes\n", nummapbrushes);
  929.     qprintf ("%5i clipbrushes\n", c_clipbrushes);
  930.     qprintf ("%5i total sides\n", nummapbrushsides);
  931.     qprintf ("%5i boxbevels\n", c_boxbevels);
  932.     qprintf ("%5i edgebevels\n", c_edgebevels);
  933.     qprintf ("%5i entities\n", num_entities);
  934.     qprintf ("%5i planes\n", nummapplanes);
  935.     qprintf ("%5i areaportals\n", c_areaportals);
  936.     qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
  937.         map_maxs[0],map_maxs[1],map_maxs[2]);
  938.  
  939. //    TestExpandBrushes ();
  940. }
  941.  
  942.  
  943. //====================================================================
  944.  
  945.  
  946. /*
  947. ================
  948. TestExpandBrushes
  949.  
  950. Expands all the brush planes and saves a new map out
  951. ================
  952. */
  953. void TestExpandBrushes (void)
  954. {
  955.     FILE    *f;
  956.     side_t    *s;
  957.     int        i, j, bn;
  958.     winding_t    *w;
  959.     char    *name = "expanded.map";
  960.     mapbrush_t    *brush;
  961.     vec_t    dist;
  962.  
  963.     printf ("writing %s\n", name);
  964.     f = fopen (name, "wb");
  965.     if (!f)
  966.         Error ("Can't write %s\b", name);
  967.  
  968.     fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
  969.  
  970.     for (bn=0 ; bn<nummapbrushes ; bn++)
  971.     {
  972.         brush = &mapbrushes[bn];
  973.         fprintf (f, "{\n");
  974.         for (i=0 ; i<brush->numsides ; i++)
  975.         {
  976.             s = brush->original_sides + i;
  977.             dist = mapplanes[s->planenum].dist;
  978.             for (j=0 ; j<3 ; j++)
  979.                 dist += fabs( 16 * mapplanes[s->planenum].normal[j] );
  980.  
  981.             w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist);
  982.  
  983.             fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
  984.             fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
  985.             fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
  986.  
  987.             fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
  988.             FreeWinding (w);
  989.         }
  990.         fprintf (f, "}\n");
  991.     }
  992.     fprintf (f, "}\n");
  993.  
  994.     fclose (f);
  995.  
  996.     Error ("can't proceed after expanding brushes");
  997. }
  998.